//Francisco "Kiko" Olvera
//Player moves around on tiles and collects artifacts
//Player.h

#include "Player.h"
#include "Tile.h"
#include "ENUM.h"
#include "Controller.h"
#include "Definitions.h"
extern int g_CamPos;

Player::Player()
{
	board			= Controller::Instance()->getBoard();
	Orientation		= NORTH;
	TilePos			= XY(TILE_MID);
	//HomeSpace		= XY(TILE_MID);
	Alive			= false;
	numPlayerCards	= NUM_CARD_SPRITES;
}

void Player::Init(char* texture, XY position, int direction, Card** a_card, int numCards)
{
	//Load the texture for the player mesh
	mesh.Load(texture);

	//Set the player mesh's position on the board
	SetBoardPosition(position);

	//Set the player's home space to where they are first spawned
	HomeSpace = board->getTile(position);

	//Set the player mesh's direction
	SetOrientation(direction);

	//Initialize the current player's cards appropriately
	playerCards = a_card;
	numPlayerCards = numCards;
}

//move player to specific tile position if possible
//if not returns false
bool Player::SetTilePosition(XY pos)
{
	//find out which type of tile the player is on
	int t_Type = CurrentTile->getType();
	//find out which direction its facing
	int t_Orientation = CurrentTile->getOrientation();

	//just determines if it is or not a valid position for a player
	switch(t_Type)
	{
	case STRAIGHT:
		{
			switch(t_Orientation)
			{
			case NORTH:
			case SOUTH:
				{
					if(pos.X == TILE_MID)
					{
						TilePos = pos;
						return true;
					}
				}
				break;
			case EAST:
			case WEST:
				{
					if(pos.Y == TILE_MID)
					{
						TilePos = pos;
						return true;
					}
				}
				break;
			};
		}
		break;
	case ELBOW:
		{
			switch(t_Orientation)
			{
			case NORTH:
				{
					if(
						(pos.X == TILE_MID && pos.Y > TILE_MIN) ||
						(pos.X == TILE_MAX && pos.Y == TILE_MID)
					  )
					{
						TilePos = pos;
						return true;
					}
				}
				break;
			case SOUTH:
				{
					if(
						(pos.X == TILE_MID && pos.Y < TILE_MAX) ||
						(pos.X == TILE_MIN && pos.Y == TILE_MID)
					  )
					{
						TilePos = pos;
						return true;
					}
				}
				break;
			case EAST:
				{
					if(
						(pos.X == TILE_MID && pos.Y > TILE_MIN) ||
						(pos.X == TILE_MIN && pos.Y == TILE_MID)
					  )
					{
						TilePos = pos;
						return true;
					}
				}
				break;
			case WEST:
				{
					if(
						(pos.X == TILE_MID && pos.Y < TILE_MAX) ||
						(pos.X == TILE_MAX && pos.Y == TILE_MID)
					  )
					{
						TilePos = pos;
						return true;
					}
				}
				break;
			};
		}
		break;
	case THREEWAY:
		{
			switch(t_Orientation)
			{
			case NORTH:
				{
					if(
						(pos.Y == TILE_MID) ||
						(pos.X == TILE_MID && pos.Y == TILE_MIN)
					  )
					{
						TilePos = pos;
						return true;
					}
				}
				break;
			case SOUTH:
				{
					if(
						(pos.Y == TILE_MID) ||
						(pos.X == TILE_MID && pos.Y == TILE_MAX)
					  )
					{
						TilePos = pos;
						return true;
					}
				}
				break;
			case EAST:
				{
					if(
						(pos.X == TILE_MID) ||
						(pos.X == TILE_MAX && pos.Y == TILE_MID)
					  )
					{
						TilePos = pos;
						return true;
					}
				}
				break;
			case WEST:
				{
					if(
						(pos.X == TILE_MID) ||
						(pos.X == TILE_MIN && pos.Y == TILE_MID)
					  )
					{
						TilePos = pos;
						return true;
					}
				}
				break;
			};
		}
		break;
	};
	return false;
}

//player movement
//either moves player to new position or returns false
bool Player::MoveRealNorth()
{
	Orientation = NORTH;
	if(TilePos.Y == TILE_MIN && TilePos.X != TILE_MID)
		return false;
	if(TilePos.Y == TILE_MIN)
	{
		Tile* north = board->getRealNorth();
		if(!north)
			return false;
		int tType = north->getType();
		int tOrientation = north->getOrientation();
		switch(tType)
		{
		case STRAIGHT:
			{
				if(tOrientation == EAST || tOrientation == WEST)
					return false;
				else
				{
					CurrentTile = north;
					return SetTilePosition(XY(TILE_MID,TILE_MAX));
				}
			}
			break;
		case ELBOW:
			{
				if(tOrientation == SOUTH || tOrientation == WEST)
					return false;
				else
				{
					CurrentTile = north;
					return SetTilePosition(XY(TILE_MID,TILE_MAX));
				}
			}
			break;
		case THREEWAY:
			{
				if(tOrientation == NORTH)
					return false;
				else
				{
					CurrentTile = north;
					return SetTilePosition(XY(TILE_MID,TILE_MAX));
				}
			}
			break;
		};
	}

	XY move(TilePos.X, TilePos.Y-1);
	return SetTilePosition(move);
}

bool Player::MoveRealSouth()
{
	Orientation = SOUTH;
	if(TilePos.Y == TILE_MAX && TilePos.X != TILE_MID)
		return false;
	if(TilePos.Y == TILE_MAX)
	{
		Tile* south = board->getRealSouth();
		if(!south)
			return false;
		int tType = south->getType();
		int tOrientation = south->getOrientation();
		switch(tType)
		{
		case STRAIGHT:
			{
				if(tOrientation == EAST || tOrientation == WEST)
					return false;
				else
				{
					CurrentTile = south;
					return SetTilePosition(XY(TILE_MID,TILE_MIN));
				}
			}
			break;
		case ELBOW:
			{
				if(tOrientation == NORTH || tOrientation == EAST)
					return false;
				else
				{
					CurrentTile = south;
					return SetTilePosition(XY(TILE_MID,TILE_MIN));
				}
			}
			break;
		case THREEWAY:
			{
				if(tOrientation == SOUTH)
					return false;
				else
				{
					CurrentTile = south;
					return SetTilePosition(XY(TILE_MID,TILE_MIN));
				}
			}
			break;
		};
	}

	XY move(TilePos.X, TilePos.Y+1);
	return SetTilePosition(move);
}

bool Player::MoveRealEast()
{
	Orientation = EAST;
	if(TilePos.X == TILE_MAX && TilePos.Y != TILE_MID)
		return false;
	if(TilePos.X == TILE_MAX)
	{
		Tile* east = board->getRealEast();
		if(!east)
			return false;
		int tType = east->getType();
		int tOrientation = east->getOrientation();
		switch(tType)
		{
		case STRAIGHT:
			{
				if(tOrientation == NORTH || tOrientation == SOUTH)
					return false;
				else
				{
					CurrentTile = east;
					return SetTilePosition(XY(TILE_MIN,TILE_MID));
				}
			}
			break;
		case ELBOW:
			{
				if(tOrientation == NORTH || tOrientation == WEST)
					return false;
				else
				{
					CurrentTile = east;
					return SetTilePosition(XY(TILE_MIN,TILE_MID));
				}
			}
			break;
		case THREEWAY:
			{
				if(tOrientation == EAST)
					return false;
				else
				{
					CurrentTile = east;
					return SetTilePosition(XY(TILE_MIN,TILE_MID));
				}
			}
			break;
		};
	}

	XY move(TilePos.X+1, TilePos.Y);
	return SetTilePosition(move);
}

bool Player::MoveRealWest()
{
	Orientation = WEST;
	if(TilePos.X == TILE_MIN && TilePos.Y != TILE_MID)
		return false;
	if(TilePos.X == TILE_MIN)
	{
		Tile* west = board->getRealWest();
		if(!west)
			return false;
		int tType = west->getType();
		int tOrientation = west->getOrientation();
		switch(tType)
		{
		case STRAIGHT:
			{
				if(tOrientation == NORTH || tOrientation == SOUTH)
					return false;
				else
				{
					CurrentTile = west;
					return SetTilePosition(XY(TILE_MAX,TILE_MID));
				}
			}
			break;
		case ELBOW:
			{
				if(tOrientation == SOUTH || tOrientation == EAST)
					return false;
				else
				{
					CurrentTile = west;
					return SetTilePosition(XY(TILE_MAX,TILE_MID));
				}
			}
			break;
		case THREEWAY:
			{
				if(tOrientation == WEST)
					return false;
				else
				{
					CurrentTile = west;
					return SetTilePosition(XY(TILE_MAX,TILE_MID));
				}
			}
			break;
		};
	}

	XY move(TilePos.X-1, TilePos.Y);
	return SetTilePosition(move);
}

bool Player::MoveNorth()
{
	switch(g_CamPos)
	{
	case CAM_NORTH:	return MoveRealSouth();
	case CAM_SOUTH:	return MoveRealNorth();
	case CAM_EAST:	return MoveRealWest();
	case CAM_WEST:	return MoveRealEast();
	}
	return false;
}

bool Player::MoveSouth()
{
	switch(g_CamPos)
	{
	case CAM_NORTH:	return MoveRealNorth();
	case CAM_SOUTH:	return MoveRealSouth();
	case CAM_EAST:	return MoveRealEast();
	case CAM_WEST:	return MoveRealWest();
	}
	return false;
}

bool Player::MoveEast()
{
	switch(g_CamPos)
	{
	case CAM_NORTH:	return MoveRealWest();
	case CAM_SOUTH:	return MoveRealEast();
	case CAM_EAST:	return MoveRealNorth();
	case CAM_WEST:	return MoveRealSouth();
	}
	return false;
}

bool Player::MoveWest()
{
	switch(g_CamPos)
	{
	case CAM_NORTH:	return MoveRealEast();
	case CAM_SOUTH:	return MoveRealWest();
	case CAM_EAST:	return MoveRealSouth();
	case CAM_WEST:	return MoveRealNorth();
	}
	return false;
}

void Player::ForceMoveNorth()
{
	if(TilePos.Y == TILE_MIN)
	{
		Tile* north = board->getN();
		if(!north)
			return;
		CurrentTile = north;
		TilePos = XY(TilePos.X, TILE_MAX);
		return;
	}
	TilePos = XY(TilePos.X, TilePos.Y-1);
}

void Player::ForceMoveSouth()
{
	if(TilePos.Y == TILE_MAX)
	{
		Tile* south = board->getS();
		if(!south)
			return;
		CurrentTile = south;
		TilePos = XY(TilePos.X, TILE_MIN);
		return;
	}
	TilePos = XY(TilePos.X, TilePos.Y+1);
}

void Player::ForceMoveEast()
{
	if(TilePos.X == TILE_MAX)
	{
		Tile* east = board->getE();
		if(!east)
			return;
		CurrentTile = east;
		TilePos = XY(TILE_MIN, TilePos.Y);
		return;
	}
	TilePos = XY(TilePos.X+1, TilePos.Y);
}

void Player::ForceMoveWest()
{
	if(TilePos.X == TILE_MIN)
	{
		Tile* west = board->getW();
		if(!west)
			return;
		CurrentTile = west;
		TilePos = XY(TILE_MAX, TilePos.Y);
		return;
	}
	TilePos = XY(TilePos.X-1, TilePos.Y);
}

//move player to center of given tile
void Player::SetBoardPosition(Tile* tile)
{
	CurrentTile = tile;
	//guaranteed safe spot for all tiles
	TilePos = XY(TILE_MID);
}

void Player::SetBoardPosition(XY pos)
{
	CurrentTile = board->getTile(pos);
	//guaranteed safe spot for all tiles
	TilePos = XY(TILE_MID);
}

void Player::SetCards(Card** newCards)
{
	playerCards = newCards;
}


bool Player::isHome()
{
	if(CurrentTile == HomeSpace)
	{
		return true;
	}
	else
	{
		return false;
	}
}

bool Player::Collect()
{
	if(numPlayerCards > 0)
	{
		if(CurrentTile->getArtifact() == playerCards[numPlayerCards-1]->GetArtifact())
		{
			CurrentTile->getArtifact()->Take();
			playerCards[numPlayerCards-1] = NULL;
			numPlayerCards--;
			return true;
		}
	}
	return false;
}

//draws the mesh at the current position on board and tile
void Player::Draw()
{
	XY boardPos = CurrentTile->getBoardPos();
	//center of current tile
	float X = boardPos.X*TILE_SIZE;
	float Y = boardPos.Y*(-TILE_SIZE);
	//top left of current tile
	X-=TILE_POS_SIZE;
	Y+=TILE_POS_SIZE;
	//correct position in current tile
	X += TILE_POS_SIZE*TilePos.X;
	Y -= TILE_POS_SIZE*TilePos.Y;
	//draw mesh at correct point in space facing correct direction
	mesh.Draw(X, Y, Orientation);
}

void Player::DrawCards(Sprite* sprite)
{
	int xDist = SCREEN_WIDTH/13;
	int yDist = SCREEN_HEIGHT/20;
	SpriteInfo* info;
	SpriteInfo* blank = Controller::Instance()->getBlankSprite();
	for(int i=0;i<numPlayerCards;++i)
	{
		info = playerCards[i]->GetSpriteInfo();
		if(playerCards[i]->isFlipped())
		{
			//info->setScale(0.25f);
			info->setPosOfCenter( xDist*(i+1), yDist );
			sprite->Draw(*info);
		}
		else
		{
			blank->setPosOfCenter( xDist*(i+1), yDist );
			sprite->Draw(*blank);
		}
	}
}

void Player::ShowCard()
{
	playerCards[numPlayerCards-1]->GetSpriteInfo()->setScale(0.25f);
	playerCards[numPlayerCards-1]->Flip(true);
}

void Player::ShowAllCards()
{
	for(int i = 0; i < numPlayerCards; i++)
	{
		playerCards[i]->Flip(true);
	}
}

void Player::HideCard()
{
	if(numPlayerCards > 0)
	{
		playerCards[numPlayerCards-1]->Flip(false);
	}
}

void Player::HideAllCards()
{
	for(int i = 0; i < numPlayerCards; i++)
	{
		playerCards[i]->Flip(false);
	}
}